package joindemo.domain.query;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.media.Schema;
import joindemo.common.constants.MybatisConstant;
import joindemo.exception.ServiceException;
import joindemo.utils.SqlUtil;
import joindemo.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * 分页查询基类
 * 集成MyBatis-Plus分页构建与安全排序逻辑
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "分页查询基础参数")
public class PageQuery implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    @Schema(description = "当前页码", defaultValue = "1")
    private Integer pageNo;

    @Schema(description = "每页条数", defaultValue = "10")
    private Integer pageSize;

    @Schema(description = "排序字段 (支持驼峰命名，如 createTime)")
    private String sortField;

    @Schema(description = "排序规则 (asc/desc/ascending/descending)", defaultValue = "desc")
    private String sortOrder;

    /**
     * 构建 MyBatis-Plus 分页对象
     *
     * @param <T> 实体类型
     * @return Page对象
     */
    public <T> Page<T> build() {
        Integer pageNum = ObjectUtil.defaultIfNull(this.pageNo, MybatisConstant.DEFAULT_PAGE_NUM);
        Integer size = ObjectUtil.defaultIfNull(this.pageSize, MybatisConstant.DEFAULT_PAGE_SIZE);

        // 限制最大分页大小，防止恶意请求
        if (size > MybatisConstant.MAX_PAGE_SIZE) {
            size = MybatisConstant.MAX_PAGE_SIZE;
        }
        if (pageNum <= 0) {
            pageNum = MybatisConstant.DEFAULT_PAGE_NUM;
        }

        Page<T> page = new Page<>(pageNum, size);
        
        // 构建排序条件
        List<OrderItem> orderItems = buildOrderItem();
        if (CollUtil.isNotEmpty(orderItems)) {
            page.addOrder(orderItems);
        }
        
        return page;
    }

    /**
     * 解析并构建排序条目
     * 支持多字段排序，格式兼容：
     * 1. 单字段: sortField="createTime", sortOrder="desc"
     * 2. 多字段: sortField="createTime,id", sortOrder="desc,asc"
     */
    private List<OrderItem> buildOrderItem() {
        if (StringUtils.isBlank(sortField)) {
            return null;
        }
        
        // 默认降序
        if (StringUtils.isBlank(sortOrder)) {
            sortOrder = MybatisConstant.SORT_ORDER_DESC;
        }

        // 防止SQL注入，过滤非法字符
        String orderBy = SqlUtil.escapeOrderBySql(sortField);
        // 驼峰转下划线 (createTime -> create_time)
        orderBy = StringUtils.toUnderScoreCase(orderBy);

        // 兼容前端排序传参 (ascending -> asc, descending -> desc)
        String normalizedOrder = StringUtils.replaceEach(sortOrder, 
                new String[]{"ascending", "descending"}, 
                new String[]{MybatisConstant.SORT_ORDER_ASC, MybatisConstant.SORT_ORDER_DESC});

        String[] orderByArr = orderBy.split(StringUtils.SEPARATOR);
        String[] sortOrderArr = normalizedOrder.split(StringUtils.SEPARATOR);

        // 校验字段数与排序规则数是否匹配
        if (sortOrderArr.length != 1 && sortOrderArr.length != orderByArr.length) {
            throw new ServiceException("排序参数格式错误，字段与规则数量不匹配");
        }

        List<OrderItem> list = new ArrayList<>();
        for (int i = 0; i < orderByArr.length; i++) {
            String column = orderByArr[i];
            // 如果规则只有一个（如 "desc"），则应用到所有字段；否则一一对应
            String order = sortOrderArr.length == 1 ? sortOrderArr[0] : sortOrderArr[i];

            if (MybatisConstant.SORT_ORDER_ASC.equalsIgnoreCase(order)) {
                list.add(OrderItem.asc(column));
            } else if (MybatisConstant.SORT_ORDER_DESC.equalsIgnoreCase(order)) {
                list.add(OrderItem.desc(column));
            } else {
                throw new ServiceException("无效的排序规则: " + order);
            }
        }
        return list;
    }
}